import { App } from "../../application";
import Events from "../../application/constants/Events";
import { InteractionEvent } from "../../processor/Mouse";
import {LineGeometry} from "three/examples/jsm/lines/LineGeometry";
import {LineMaterial} from "three/examples/jsm/lines/LineMaterial";
import {Line2} from "three/examples/jsm/lines/Line2";
import { Color, Vector3 } from "three";
import { HtmlMarker, Poi, Point } from "../../Engine";

export default class HeightAnalysis {
    private app: App;
    private geometry: LineGeometry;
    private lineMaterial: LineMaterial;
    private positionArray: Array<number>;
    private pointArray: Array<Point>;
    private colorArray: Array<number>;
    private lineColor;
    private line: Line2;
    private position;
    private height;
    private labelArray: Array<HtmlMarker> = new Array<HtmlMarker>();
    private isOpenAnalysis: boolean = false;

    /**
     * 测高
     * @example var meterDistance = new GE.HeightAnalysis();
       meterDistance = new GE.HeightAnalysis();
       meterDistance.openAnalysis({color: '#00FA9A', lineWidth: 1}); //开启测高
       //meterDistance.closeAnalysis(); //关闭测高
     */
    constructor(){
        this.app = App.getInstance();
    }

    /**
     * 开启测高
     * @param param: 测高需要用到的参数
     * @param param.color: 测高线的颜色
     * @param param.lineWidth: 测高线的宽度
     * @example meterDistance.openAnalysis({color: '#00FA9A', lineWidth: 1})
     */
    public openAnalysis(param: {color?: string, lineWidth?: number}){
        if(this.isOpenAnalysis){
            return;
        }
        this.positionArray = new Array<number>();
        this.pointArray = new Array<Point>();
        this.colorArray = new Array<number>();

        this.lineColor = new Color(param.color || '0x000000');
        this.geometry = new LineGeometry();

        this.lineMaterial = new LineMaterial( {
			color: this.lineColor,
			linewidth: param.lineWidth || 1, // in world units with size attenuation, pixels otherwise
			vertexColors: true,
			dashed: false,
			alphaToCoverage: true,
            transparent: true,
            depthTest: false
		});
        this.lineMaterial.fog = true;
        this.line = new Line2( this.geometry, this.lineMaterial );
        this.lineMaterial.resolution.set( window.innerWidth, window.innerHeight ); // resolution of the viewport
		this.line.scale.set( 1, 1, 1 );
        this.line.renderOrder = 1000;
		this.app.three.scene.add( this.line );

        this.register();
        this.isOpenAnalysis = true;
    }

    /**
     * 关闭在地图上测距的线
     * @example meterDistance.closeAnalysis()
     */
    public closeAnalysis(){
        this.positionArray.splice(0, this.positionArray.length)
        this.pointArray.splice(0, this.pointArray.length);
        this.colorArray.splice(0, this.colorArray.length);

        this.app.three.scene.remove( this.line );
        let self = this;
        this.labelArray.forEach(label => {
            self.app.three.scene.remove( label );
        });
        this.labelArray = [];
        this.isOpenAnalysis = false;
    }

    /**
     * 获取在地图上测高的值
     * @returns 测高的值
     * @example meterDistance.getHeight()
     */
    public getHeight(){
        return this.height;
    }

    private register() {
        this.app.on(Events.Click, this.handleLeftClickEvent, this);
        this.app.on(Events.MouseMove, this.handleMoveEvent, this);
        
        this.app.mouse.addRaycasterType(Events.MouseMove);  //开启鼠标移动时的射线拾取功能
    }

    private measureHeight(){
        let height = 0;
        let firstPoint = this.pointArray[0];
        let secondPoint = this.pointArray[1];
        height = Math.abs(secondPoint.z - firstPoint.z);
        //为height保留两位小数
        height = Number(height.toFixed(2)); //Math.round(height * 100) / 100;
        return height;
    }

    private cancleEvent(){
        this.app.off(Events.Click, this.handleLeftClickEvent, this);
        this.app.off(Events.MouseMove, this.handleMoveEvent, this);

        this.app.mouse.removeRaycasterType(Events.MouseMove);  //关闭鼠标移动时的射线拾取功能
    }

    private handleLeftClickEvent(data: InteractionEvent) {
        let clickPoint:Point = data.lnglat.clone();
        clickPoint.toEPSGWeb();
        let originPoint = clickPoint.clone();
        
        if(this.pointArray.length == 0){
            this.line.position.copy(clickPoint);
            this.position = clickPoint.clone();
        }
        clickPoint = clickPoint.sub(this.position);
        this.pointArray.push(clickPoint);

        if(this.pointArray.length > 1){
            this.cancleEvent();
            
            this.height = this.measureHeight();

            this.positionArray.push(this.positionArray[0], this.positionArray[1], clickPoint.z);
            this.colorArray.push(this.lineColor.r, this.lineColor.g, this.lineColor.b);

            this.positionArray.push(this.positionArray[0], this.positionArray[1], this.positionArray[2]);
            this.colorArray.push(this.lineColor.r, this.lineColor.g, this.lineColor.b);

            let markerMsg = {distance: this.height, point: originPoint};
            this.htmlMarker(markerMsg);
        }else{
            this.positionArray.push(clickPoint.x, clickPoint.y, clickPoint.z);
            this.colorArray.push(this.lineColor.r, this.lineColor.g, this.lineColor.b);
    
            this.positionArray.push(clickPoint.x, clickPoint.y, clickPoint.z);
            this.colorArray.push(this.lineColor.r, this.lineColor.g, this.lineColor.b);
        }

        //必须要先调用geometry.dispose函数，然后新建一个几何体。因为geometry.setPositions函数会创建一个缓冲区，而且这个缓冲区不能被修改.
        this.geometry.dispose();
        this.geometry = new LineGeometry();
        this.geometry.setPositions( this.positionArray );
        this.geometry.setColors( this.colorArray );

        this.line.geometry = this.geometry;

        try {
            if(this.positionArray.length > 3){
                this.line.computeLineDistances();
            }
            
        } catch (error) {
            console.log(error);
        }
    }

    private handleMoveEvent(data: InteractionEvent) {
        if(this.positionArray.length < 3){
            return;
        }
        let clickPoint:Point = data.lnglat.clone();
        clickPoint.toEPSGWeb();
        clickPoint = clickPoint.sub(this.position);

        let positionIndex = this.positionArray.length;
        this.positionArray[positionIndex - 3] = clickPoint.x;
        this.positionArray[positionIndex - 2] = clickPoint.y;
        this.positionArray[positionIndex - 1] = clickPoint.z;
        this.geometry.setPositions( this.positionArray );

        let positionAttribute = this.geometry.getAttribute("position");
        positionAttribute.needsUpdate = true;
    }

    private htmlMarker(markerMsg: {distance: number, point: Point}) {
        //初始化要显示的标注的html内容
        let div = document.createElement('div');
        div.className = 'label';
        div.textContent = 'HTMLMarker';
        div.style.backgroundColor = 'transparent';
        let distance = Number(markerMsg.distance);
        if(distance < 1000){
            div.innerText = '高度：' + distance.toFixed(2) + '米';
        }else{
            distance = distance / 1000;
            div.innerText = '高度：' + distance.toFixed(2) + '公里';
        }

        let color = '#' + this.lineColor.getHexString();
        div.style.color = color;

        //设置组件在三维场景中的位置
        let position = markerMsg.point.toEPSGWeb();
        //初始化标注组件，并将htmlelement作为参数传入，这里是一个div
        let label = new HtmlMarker(div, {position: position, isCollisionCheck: false});
        //设置对其方式，0,0为中心对齐
        label.center.set(0, 0);
        //将组件添加至场景中
        this.app.add(label);
        this.labelArray.push(label);
    }
}